package com.etoak.stock.security.filter;

import com.etoak.stock.constant.StockConstant;
import com.etoak.stock.security.user.LoginUserDetail;
import com.etoak.stock.security.utils.JwtTokenUtil;
import com.etoak.stock.vo.req.LoginReqVo;
import com.etoak.stock.vo.resp.LoginRespVoExt;
import com.etoak.stock.vo.resp.R;
import com.etoak.stock.vo.resp.ResponseCode;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;

/**
 * @Author by 孙有泽
 * @Date 2024/11/10 9:38
 * @Description 认证过滤器 核心作用 认证用户信息并且颁发票据
 */

public class JwtLoginAuthenticationFilter extends AbstractAuthenticationProcessingFilter {


    private RedisTemplate redisTemplate;

    /*
     * @description 自定义构造器 传入登录认证的url
     */

    public JwtLoginAuthenticationFilter(String defaultFilterProcessesUrl) {
        super(defaultFilterProcessesUrl);
    }
    public void setRedisTemplate(RedisTemplate redisTemplate){
        this.redisTemplate = redisTemplate;
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException, IOException, ServletException, IOException {
       //判断请求方式必须是post 且提交的数据内容必须是application/json
        if(!request.getMethod().equalsIgnoreCase("POST")||!MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(request.getContentType())){
            throw  new AuthenticationServiceException("Authentication method not supported: " + request.getMethod());
        }
        //获取post请求ajax提交的数据
        LoginReqVo loginReqVo = new ObjectMapper().readValue(request.getInputStream(), LoginReqVo.class);
        //校验输入的验证码是否正确
        String redisCode = (String)redisTemplate.opsForValue().get(StockConstant.CHECK_PREFIX + loginReqVo.getSessionId());
        //设置响应的格式和编码
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("UTF-8");
        if(redisCode==null||!redisCode.equalsIgnoreCase(loginReqVo.getCode())){
            //响应验证码输入错误
            R<Object> error = R.error(ResponseCode.CHECK_CODE_ERROR.getMessage());
            //给前端错误的提示
            response.getWriter().write(new ObjectMapper().writeValueAsString(error));
            return null;
        }
        String username = loginReqVo.getUsername();
        username=(username!=null)?username:"";
        username=username.trim();
        String password = loginReqVo.getPassword();
        password=(password!=null)?password:"";
        //组装认证票据对象
        UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(username, password);
        //将认证票据对象交给认证管理器进行认证
        return this.getAuthenticationManager().authenticate(usernamePasswordAuthenticationToken);
    }
    /*
     * @author 孙有泽
     * @date 2024/12/23 21:36
     * @description 响应成功
     */

    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication authResult) throws IOException, ServletException {
        LoginUserDetail principal = (LoginUserDetail) authResult.getPrincipal();
        String username = principal.getUsername();
        List<GrantedAuthority> authorities = principal.getAuthorities();
        String token = JwtTokenUtil.createToken(username, authorities.toString());
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("UTF-8");
        LoginRespVoExt loginRespVoExt = new LoginRespVoExt();
        BeanUtils.copyProperties(principal,loginRespVoExt);
        loginRespVoExt.setAccessToken(token);
        R<LoginRespVoExt> ok = R.ok(loginRespVoExt);
        response.getWriter().write(new ObjectMapper().writeValueAsString(ok));


    }
    /*
     * @author 孙有泽
     * @date 2024/12/23 21:36
     * @description 响应失败的处理
     */

    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException failed) throws IOException, ServletException {
        response.setContentType(MediaType.APPLICATION_JSON_VALUE);
        response.setCharacterEncoding("UTF-8");
        R<Object> error = R.error(ResponseCode.ERROR);
        response.getWriter().write(new ObjectMapper().writeValueAsString(error));
    }
}

